﻿using System;
using System.Collections;
using System.Collections.Generic;
using System.Numerics;

namespace UtilityToolsCollect.DataCollection
{
    public class HistoricalStack<T> : IEnumerable<T>
	{
		private T[] HistoricalArray;
		protected int _PushCount = 0;
		public int Count => _PushCount >= HistoricalArray.Length ? HistoricalArray.Length : _PushCount;
		public int Size => HistoricalArray.Length;
		public IEnumerator<T> GetEnumerator() { return ((IEnumerable<T>)m_Values).GetEnumerator(); }
		IEnumerator IEnumerable.GetEnumerator() { return m_Values.GetEnumerator(); }
		private void MoveData()
		{
			for (int i = HistoricalArray.Length - 2; i >= 0; i--)
				HistoricalArray[i + 1] = HistoricalArray[i];
		}
		public HistoricalStack(int Count) { HistoricalArray = new T[Count]; }

		public void Push(T Element)
		{
			MoveData();
			HistoricalArray[0] = Element;
			++_PushCount;
		}

		public T this[int index]
		{
			get
			{
				if (_PushCount >= HistoricalArray.Length)
					return HistoricalArray[index];
				if (_PushCount < 1)
					throw new IndexOutOfRangeException($"当前[{GetType().FullName}]实例，尚未储存数据");
				if (index < _PushCount)
					return HistoricalArray[index];
				throw new IndexOutOfRangeException($"索引超出范围,当前[{GetType().FullName}]实例中仅有[{_PushCount}]个数据，最大索引仅支持到[{_PushCount - 1}]，当前索引参数:[{nameof(index)}:{index}]");
			}
		}

		private T[] m_Values
		{
			get
			{
				if (_PushCount >= HistoricalArray.Length)
					return HistoricalArray;
				if (_PushCount < 1)
					return [];
				return HistoricalArray[.._PushCount];
			}
		}

		public ReadOnlySpan<T> Span => m_Values;
		public ReadOnlyMemory<T> Memory => m_Values;
	}


	public class NumberHistoricalStack<T> : HistoricalStack<T> where T : INumber<T>
	{
	    public NumberHistoricalStack(int Count) : base(Count) { }
        public NumberHistoricalStack(T[] values) : base(values.Length) { foreach (T item in values) Push(item); }
        public T SumValue
	    {
	        get
	        {
	            T current = T.Zero;
	            foreach (T item in Span)
	                current += item;
	            return current;
	        }
	    }

		public T AverageValue
		{
			get 
			{
                if (_PushCount < 1)
                    return T.Zero;

                T current = T.Zero;
                foreach (T item in Span)
                    current += item;

                return current / (T)Convert.ChangeType(Count, typeof(T));
            }
		}
		
    }
}